package com.gwlc.common.util;


import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.FatalBeanException;
import org.springframework.cglib.beans.BeanMap;
import org.springframework.util.Assert;

import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 实体工具类
 *
 * @author Lius
 * @date 2018/10/26 13:37
 */

public class BeanTool extends BeanUtils {
    public static ObjectMapper mapper = new ObjectMapper();


    public BeanTool() {
    }

    /**
     * 将List<T>转换为List<Map<String, Object>>
     *
     * @param objList List<T>集合
     * @return 返回map集合
     */
    public static <T> List<Map<String, Object>> objectsToMaps(List<T> objList) {
        List<Map<String, Object>> list = new ArrayList<>();
        if (objList != null && objList.size() > 0) {
            Map<String, Object> map;
            T bean;
            for (T t : objList) {
                bean = t;
                map = beanToMap(bean);
                list.add(map);
            }
        }
        return list;
    }

    /**
     * 将对象装换为map
     *
     * @param bean javabean
     * @return Map集合
     */
    public static <T> Map<String, Object> beanToMap(T bean) {
        Map<String, Object> map = new HashMap<>(16);
        if (bean != null) {
            BeanMap beanMap = BeanMap.create(bean);
            for (Object key : beanMap.keySet()) {
                map.put(key + "", beanMap.get(key));
            }
        }
        return map;
    }

    /**
     * 将List<Map<String,Object>>转换为List<T>
     *
     * @param maps  map集合
     * @param clazz Bean
     * @return 键值对转化为Bean的List集合
     * @throws InstantiationException 无法实例化指定的类对象
     * @throws IllegalAccessException 无权访问指定类，字段，方法或构造函数。
     */
    public static <T> List<T> mapsToObjects(List<Map<String, Object>> maps, Class<T> clazz) throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        List<T> list = new ArrayList<>();
        if (maps != null && maps.size() > 0) {
            Map<String, Object> map;
            T bean;
            for (Map<String, Object> stringObjectMap : maps) {
                map = stringObjectMap;
                bean = clazz.getDeclaredConstructor().newInstance();
                mapToBean(map, bean);
                list.add(bean);
            }
        }
        return list;
    }

    /**
     * 将map装换为javabean对象
     *
     * @param map  map
     * @param bean bean
     * @return bean对象
     */
    public static <T> T mapToBean(Map<String, Object> map, T bean) {
        BeanMap beanMap = BeanMap.create(bean);
        beanMap.putAll(map);
        return bean;
    }

    /**
     * 复制类中非空的属性到另一个类的工具
     *
     * @param source 提供数据的类
     * @param target 接收数据的类
     * @throws BeansException 类异常
     */
    public static void copyProperties(Object source, Object target) throws BeansException {
        Assert.notNull(source, "提供数据的类不能为空！！！");
        Assert.notNull(target, "接收数据的类不能为空！！！");
        Class<?> actualEditable = target.getClass();
        PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);
        for (PropertyDescriptor targetPd : targetPds) {
            if (targetPd.getWriteMethod() != null) {
                PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());
                if (sourcePd != null && sourcePd.getReadMethod() != null) {
                    try {
                        Method readMethod = sourcePd.getReadMethod();
                        if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
                            readMethod.setAccessible(true);
                        }
                        Object value = readMethod.invoke(source);
                        // 这里判断以下value是否为空 当然这里也能进行一些特殊要求的处理
                        if (value != null) {
                            Method writeMethod = targetPd.getWriteMethod();
                            if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
                                writeMethod.setAccessible(true);
                            }
                            writeMethod.invoke(target, value);
                        }
                    } catch (Throwable ex) {
                        throw new FatalBeanException("复制类失败！！！", ex);
                    }
                }
            }
        }
    }


    /**
     * 将json转化为单个map
     *
     * @param value json
     * @return map
     */
    public static Map<?, ?> jsonToMap(String value) throws JsonProcessingException {

        return mapper.readValue(value, Map.class);


    }


}